/*
 * @Description: 泛型的定义及泛型函数
 * @Autor: HuiSir<273250950@qq.com>
 * @Date: 2021-05-06 18:33:38
 * @LastEditTime: 2021-05-17 21:24:50
 */

/**
 * 泛型：使用`<T>`尖括号和字母（类型变量）来声明函数、类、接口等
 * 作用：为了使得组件的类型更加灵活，用户可以使用自己的数据类型来使用组件
 * 使用any也比较灵活，但不能保证传入类型和返回类型保持一致
 */

(function () {
    /**
     * 泛型函数
     */
    function echo<T>(arg: T): T {
        return arg
    }

    /**
     * 匿名泛型函数
     */
    let echo2 = function <T>(arg: T): T {
        return arg
    }

    /**
     * 箭头泛型函数
     */
    let echo3 = <T>(arg: T): T => {
        return arg
    }

    /**
     * 完整写法
     */
    let echo4: <T>(arg: T) => T = <T>(arg: T): T => {
        return arg
    }

    /**
     * 参数是数组的泛型函数
     */
    function echoArr<T>(arr: T[]): T[] {
        console.log(arr.length) //由于我们操作的是数组，所以.length属性是应该存在的
        return arr
    }

    /**
     * 或者使用Array<T>方式
     */
    function echoArr2<T>(arg: Array<T>): Array<T> {
        return arg
    }

    /**
     * 泛型函数赋值
     */

    let fn: <T>(arg: T) => T = echo4    //使用箭头形式定义fn变量类型
    let fn2: { <T>(arg: T): T } = fn      //使用对象字面量形式定义fn变量类型

    /**
     * 使用接口形式抽象泛型
     */
    interface iEcho<T> {
        (arg: T): T
    }

    interface iEcho2 {
        <T>(arg: T): T
    }

    let fn3: iEcho<string> = function (arg: string): string {
        return arg
    }

    let fn4: iEcho2 = function (arg) {
        return arg
    }

    /**
     * 多参数泛型函数
     */

    function test<M, N>(arg1: M, arg2: N): [M, N] {
        return [arg1, arg2]
    }

    console.log(echo("Hello World")) //Hello World
    console.log(echo2<number>(9)) //9
    console.log(echo3<boolean>(false)) //false
    console.log(echoArr<string>(["Hello", "world"])) //2, [ 'Hello', 'world' ]
    console.log(echoArr2<string>(["Hello", "world"])) //[ 'Hello', 'world' ]
    console.log(fn<string>("你好")) //你好
    console.log(fn2<string>("中国")) //中国
    console.log(fn3("I LOVE YOU")) //I LOVE YOU
    console.log(fn4<string>("I LOVE YOU")) //I LOVE YOU
    console.log(test<string, number>("Hello", 2021)) //[ 'Hello', 2021 ]
})()

